using System;
using System.Data;
using System.Text;

using SchemaExplorer;

#region 冗余配置信息
//无论数据库类型和字段格式，都用[]包含
public class RedundancyInfo
{
    public ColumnSchema RedundancyPK;
    public ColumnSchema RedundancyColumn;
    public ColumnSchema DependToPK;
    public ColumnSchema DependToSourceColumn;

    //extendedProperty: [CategoryID]=[dbo].[Categories].[CategoryID],[CategoryName]
    public RedundancyInfo(ColumnSchema redundancyColumn, string extendedProperty)
    {
        if (redundancyColumn == null || string.IsNullOrEmpty(extendedProperty))
            throw new Exception("冗余列及其扩展属性不能为空。");

        string pkSetting = extendedProperty.Substring(0, extendedProperty.IndexOf(",")); //[CategoryID]=[dbo].[Categories].[CategoryID]
        string redundancyPKColumnName = pkSetting.Substring(1, pkSetting.IndexOf("]") - 1); //CategoryID
        foreach (ColumnSchema column in redundancyColumn.Table.Columns)
        {
            if (column.Name.ToLower() == redundancyPKColumnName.ToLower())
            {
                this.RedundancyPK = column;
                break;
            }
        }
        this.RedundancyColumn = redundancyColumn;

        string dependToSourceColumnName = extendedProperty.Substring(extendedProperty.IndexOf(",") + 1); //[CategoryName]
        dependToSourceColumnName = dependToSourceColumnName.Substring(1, dependToSourceColumnName.Length - 2); //CategoryName
        string dependToColumnSetting = extendedProperty.Substring(extendedProperty.IndexOf("=") + 1); //[dbo].[Categories].[CategoryID],[CategoryName]
        dependToColumnSetting = dependToColumnSetting.Substring(0, dependToColumnSetting.IndexOf(",")); //[dbo].[Categories].[CategoryID]
        string[] dependToColumnArr = dependToColumnSetting.Split('.');
        string dependToTableName = dependToColumnArr[dependToColumnArr.Length - 2]; //[Categories]
        dependToTableName = dependToTableName.Substring(1, dependToTableName.Length - 2); //Categories
        string dependToPKColumnName = dependToColumnArr[dependToColumnArr.Length - 1]; //[CategoryID]
        dependToPKColumnName = dependToPKColumnName.Substring(1, dependToPKColumnName.Length - 2); //CategoryID
        TableSchema dependToTable = null;
        foreach (TableSchema table in redundancyColumn.Table.Database.Tables)
        {
            if (table.Name.ToLower() == dependToTableName.ToLower())
            {
                dependToTable = table;
                break;
            }
        }
        foreach (ColumnSchema column in dependToTable.Columns)
        {
            if (column.Name.ToLower() == dependToPKColumnName.ToLower())
            {
                this.DependToPK = column;
                break;
            }
        }
        foreach (ColumnSchema column in dependToTable.Columns)
        {
            if (column.Name.ToLower() == dependToSourceColumnName.ToLower())
            {
                this.DependToSourceColumn = column;
                break;
            }
        }
    }
}
#endregion

#region Database
public class ExtendedDatabase : DatabaseSchema
{
    public ExtendedDatabase(DatabaseSchema database)
        : base(database.Provider, database.ConnectionString) { }

    public string DBClassName
    {
        get { return PascalCaseName + "DB"; }
    }
    public string DaoFactoryClassName
    {
        get { return PascalCaseName + "DaoFactory"; }
    }
    public string InitializerClassName
    {
        get { return PascalCaseName + "Initializer"; }
    }
    public string TableEnumName
    {
        get { return PascalCaseName + "Table"; }
    }
    public string ViewEnumName
    {
        get { return PascalCaseName + "View"; }
    }
    public string PascalCaseName
    {
        get { return ExtenderHelper.GetPascalCaseName(base.Name); }
    }
    public string CamelCaseName
    {
        get { return ExtenderHelper.GetCamelCaseName(base.Name); }
    }
}
#endregion

#region Table
public class ExtendedTable : TableSchema
{
    public ExtendedTable(TableSchema table)
        : base(table.Database, table.Name, table.Owner, table.DateCreated, table.ExtendedProperties.ToArray()) { }

    public string EntityClassName
    {
        get { return Name.TrimEnd('s'); /* PascalCaseName */; }
    }

    public string ControllerName
    {
        get { return PascalCaseLastName; }
    }

    public string BllClassName
    {
        get { return PascalCaseName; }
    }

    public string WebServiceClassName
    {
        get { return PascalCaseName; }
    }

    public string PageName
    {
        get
        {
            return ExtenderHelper.GetUIName(this);
        }
    }

    public string PageUrl
    {
        get { return PascalCaseLastName; }
    }

    public string FileName
    {
        get { return PascalCaseLastName; }
    }

    private string PascalCaseName
    {
        get { return ExtenderHelper.GetPascalCaseName(Name); }
    }

    private string PascalCaseLastName
    {
        get { return ExtenderHelper.GetPascalCaseLastName(Name); }
    }

    private string CamelCaseName
    {
        get { return ExtenderHelper.GetCamelCaseName(Name); }
    }
}
#endregion

#region Column
public class ExtendedColumn : ColumnSchema
{
    public static string[] RESERVED_COLUMN = new string[] {
                                                    "ID",
													"Id",
                                                    "CreateTime",
													"CreateDate",
                                                    "State",
                                                    "UpdateTime",
													"UpdateDate"
                                                };

    public ExtendedColumn(ColumnSchema column)
        : base(column.Table, column.Name, column.DataType, column.NativeType, column.Size, column.Precision, column.Scale, column.AllowDBNull, column.ExtendedProperties.ToArray()) { }

    public string PropertyName
    {
        get { return PascalCaseName; }
    }

    public string FieldName
    {
        get { return CamelCaseName; }
    }

    public string UILabelName
    {
        get
        {
            return ExtenderHelper.GetUIName(this);
        }
    }

    public string ForeignKeyName
    {
        get
        {
            return this.Name.Substring(0, this.Name.Length -2);
        }
    }

    public int Order
    {
        get { return 0; }
    }

    public bool IsEnumTypeColumn
    {
        get
        {
            return base.ExtendedProperties.Contains("HG_Enum")
                && base.ExtendedProperties["HG_Enum"].Value != null
                && base.ExtendedProperties["HG_Enum"].Value.ToString() != string.Empty;
        }
    }
    //生成的枚举名，不同于指定的枚举名
    public string GeneratedEnumName
    {
        get
        {
            ExtendedTable table = new ExtendedTable(base.Table);
            return table.EntityClassName + this.PropertyName;
        }
    }
    public bool IsCustomUnique
    {
        get
        {
            if (base.ExtendedProperties.Contains("HG_IsUnique")
                && base.ExtendedProperties["HG_IsUnique"].Value != null
                && Convert.ToBoolean(base.ExtendedProperties["HG_IsUnique"].Value) == true)
                return true;

            return false;
        }
    }

    public bool IsReserved
    {
        get
        {
            foreach (string str in RESERVED_COLUMN)
            {
                if (str == Name) return true;
            }
            return false;
        }
    }

    public string CSharpNullableTypeName
    {
        get
        {
            string rtnCSType = "";
            if (rtnCSType != "string" && rtnCSType != "object" && rtnCSType != "byte[]")
            { rtnCSType += "?"; }

            return rtnCSType;
        }
    }

    public string PascalCaseName
    {
        get { return ExtenderHelper.GetPascalCaseName(base.Name); }
    }
    public string CamelCaseName
    {
        get { return ExtenderHelper.GetCamelCaseName(base.Name); }
    }
}
#endregion

#region ExtenderHelper
public class ExtenderHelper
{
    /// <summary>
    /// PREFIX_STRING -> PrefixString
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string GetPascalCaseName(string value)
    {
        string pascalValue = string.Empty;
        if (!string.IsNullOrEmpty(value))
        {
            var strArray = value.Split('_');
            foreach (var str in strArray)
            {
                if (str.Length > 1)
                {
                    pascalValue += str.Substring(0, 1).ToUpper() + str.Substring(1); //.ToLower();
                }
                else if (str.Length == 1)
                {
                    pascalValue += str.ToUpper();
                }
            }
        }

        return pascalValue;
    }

    /// <summary>
    /// PREFIX_STRING -> prefixString
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string GetCamelCaseName(string value)
    {
        if (string.IsNullOrEmpty(value))
            return value;
        else if (value.Length == 1)
            return value.ToLower();
        else
        {
            string pascalValue = GetPascalCaseName(value);
            return pascalValue.Substring(0, 1).ToLower() + pascalValue.Substring(1);
        }
    }
    /// <summary>
    /// PREFIX_STRING -> String
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string GetPascalCaseLastName(string value)
    {
        string pascalValue = string.Empty;
        if (!string.IsNullOrEmpty(value))
        {
            int index = value.IndexOf('_');
            string str;
            if (index >= 0)
            {
                str = value.Substring(index + 1);
            }
            else
            {
                str = value;
            }
            var strArray = value.Split('_');

            if (str.Length > 1)
            {
                pascalValue += str.Substring(0, 1).ToUpper() + str.Substring(1); //.ToLower();
            }
            else if (str.Length == 1)
            {
                pascalValue += str.ToUpper();
            }
        }

        return pascalValue;
    }

    /// <summary>
    /// PREFIX_STRING -> string
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string GetCamelCaseLastName(string value)
    {
        if (string.IsNullOrEmpty(value))
            return value;
        else if (value.Length == 1)
            return value.ToLower();
        else
        {
            string pascalValue = GetPascalCaseLastName(value);
            return pascalValue.Substring(0, 1).ToLower() + pascalValue.Substring(1);
        }
    }

    private static string[] UISplit = new string[] { " ", ",", "-", "，", ":", "：" };
    public static string GetUIName(TableSchema table)
    {
        var UIName = !string.IsNullOrEmpty(table.Description) ? table.Description : table.Name;
        return UIName.Split(UISplit, StringSplitOptions.RemoveEmptyEntries)[0].TrimEnd('表');
    }

    public static string GetUIName(ColumnSchema column)
    {
        var UIName = !string.IsNullOrEmpty(column.Description) ? column.Description : column.Name;
        UIName = UIName.Split(UISplit, StringSplitOptions.RemoveEmptyEntries)[0];
        if (UIName.EndsWith("Id"))
        {
            UIName = UIName.Substring(0, UIName.Length - 2);
        }
        return UIName;
    }

    public static string GetColumnLinqType(ColumnSchema column)
    {
        string rtnCSType = string.Empty;
        var dt = DbType.AnsiString; // temp
        switch (dt)
        {
            case DbType.AnsiString:
            case DbType.AnsiStringFixedLength:
            case DbType.String:
            case DbType.StringFixedLength:
            case DbType.Xml:
                rtnCSType = "string";
                break;
            case DbType.Binary:
                rtnCSType = "byte[]";
                break;
            case DbType.Boolean:
                rtnCSType = "bool";
                break;
            case DbType.Byte:
                rtnCSType = "byte";
                break;
            case DbType.Currency:
            case DbType.Decimal:
            case DbType.VarNumeric:
                rtnCSType = "decimal";
                break;
            case DbType.Date:
            case DbType.DateTime:
                rtnCSType = "DateTime";
                break;
            case DbType.Double:
                rtnCSType = "double";
                break;
            case DbType.Guid:
                rtnCSType = "Guid";
                break;
            case DbType.Int16:
                rtnCSType = "short";
                break;
            case DbType.Int32:
                rtnCSType = "int";
                break;
            case DbType.Int64:
                rtnCSType = "long";
                break;
            case DbType.Object:
                rtnCSType = "object";
                break;
            case DbType.SByte:
                rtnCSType = "sbyte";
                break;
            case DbType.Single:
                rtnCSType = "float";
                break;
            case DbType.Time:
                rtnCSType = "TimeSpan";
                break;
            case DbType.UInt16:
                rtnCSType = "ushort";
                break;
            case DbType.UInt32:
                rtnCSType = "uint";
                break;
            case DbType.UInt64:
                rtnCSType = "ulong";
                break;
            default:
                break;
        }
        return rtnCSType;
    }
    public static string GetSqlDbType(string nativeType)
    {
        string rtnType = string.Empty;
        switch (nativeType)
        {
            case "bigint":
                rtnType = "BigInt";
                break;
            case "binary":
                rtnType = "Binary";
                break;
            case "bit":
                rtnType = "Bit";
                break;
            case "char":
                rtnType = "Char";
                break;
            case "decimal":
                rtnType = "Decimal";
                break;
            case "double":
            case "float":
                rtnType = "Float";
                break;
            case "int":
                rtnType = "Int";
                break;
            case "datetime":
                rtnType = "DateTime";
                break;
            case "image":
                rtnType = "Image";
                break;
            case "money":
                rtnType = "Money";
                break;
            case "nchar":
                rtnType = "NChar";
                break;
            case "ntext":
                rtnType = "NText";
                break;
            case "numeric":
                rtnType = "Money";
                break;
            case "nvarchar":
                rtnType = "NVarChar";
                break;
            case "real":
                rtnType = "Real";
                break;
            case "smalldatetime":
                rtnType = "SmallDateTime";
                break;
            case "smallint":
                rtnType = "SmallInt";
                break;
            case "smallmoney":
                rtnType = "SmallMoney";
                break;
            case "sql_variant":
                rtnType = "Variant";
                break;
            case "text":
                rtnType = "Text";
                break;
            case "timestamp":
                rtnType = "Timestamp";
                break;
            case "tinyint":
                rtnType = "TinyInt";
                break;
            case "uniqueidentifier":
                rtnType = "UniqueIdentifier";
                break;
            case "varbinary":
                rtnType = "VarBinary";
                break;
            case "varchar":
                rtnType = "VarChar";
                break;
            case "xml":
                rtnType = "Xml";
                break;
            default:
                break;
        }
        return rtnType;
    }
    public static string GetDbDataReaderMethodName(DbType dt)
    {
        string rtnMethod = string.Empty;
        switch (dt)
        {
            case DbType.AnsiString:
            case DbType.AnsiStringFixedLength:
            case DbType.String:
            case DbType.StringFixedLength:
            case DbType.Xml:
                rtnMethod = "GetString";
                break;
            case DbType.Binary:
                rtnMethod = "GetValue";
                break;
            case DbType.Boolean:
                rtnMethod = "GetBoolean";
                break;
            case DbType.Byte:
                rtnMethod = "GetByte";
                break;
            case DbType.Currency:
            case DbType.Decimal:
            case DbType.VarNumeric:
                rtnMethod = "GetDecimal";
                break;
            case DbType.Time:
            case DbType.Date:
            case DbType.DateTime:
                rtnMethod = "GetDateTime";
                break;
            case DbType.Double:
                rtnMethod = "GetDouble";
                break;
            case DbType.Guid:
                rtnMethod = "GetGuid";
                break;
            case DbType.Int16:
                rtnMethod = "GetInt16";
                break;
            case DbType.Int32:
                rtnMethod = "GetInt32";
                break;
            case DbType.Int64:
                rtnMethod = "GetInt64";
                break;
            case DbType.Object:
                rtnMethod = "GetValue";
                break;
            case DbType.SByte:
                rtnMethod = "GetByte";
                break;
            case DbType.Single:
                rtnMethod = "GetFloat";
                break;
            case DbType.UInt16:
                rtnMethod = "GetInt16";
                break;
            case DbType.UInt32:
                rtnMethod = "GetInt32";
                break;
            case DbType.UInt64:
                rtnMethod = "GetInt64";
                break;
            default:
                break;
        }
        return rtnMethod;
    }
}
#endregion

